// -*- coding: utf-8 -*- 
/**
 * Project: PICProcess
 *
 * @author: yanking
 * Create time: 2022-04-21 16:16
 * IDE: IntelliJ IDEA
 * Introduction:
 */
package AE.MeanFilter;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;

/**
 * 实现图像的均值滤波
 */
@SuppressWarnings("ALL")
class MF {
    private final static int R = 0b00000000_00000000_00000000_11111111;
    private final static int G = 0b00000000_00000000_11111111_00000000;
    private final static int B = 0b00000000_11111111_00000000_00000000;

    // 图片平滑器,均值滤波 -> 灰度图
    // 平滑区域3 * 3
    public static int[][] imageSmoother(int[][] img) {
        /*-----构造二维前缀和数组-----*/
        int n = img.length, m = img[0].length;
        int[][] sum = new int[n + 1][m + 1];
        int[][] res = new int[n][m];
        int Alpha = 0b11111111;

        long[][] red = new long[n + 1][m + 1];
        long[][] blue = new long[n + 1][m + 1];
        long[][] green = new long[n + 1][m + 1];
        /*-----前缀和构造-----*/
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                red[i][j] = red[i - 1][j] + red[i][j - 1] - red[i - 1][j - 1] + (img[i - 1][j - 1] & R);
                green[i][j] = green[i - 1][j] + green[i][j - 1] - green[i - 1][j - 1] + ((img[i - 1][j - 1] & G) >> 8);
                blue[i][j] = blue[i - 1][j] + blue[i][j - 1] - blue[i - 1][j - 1] + ((img[i - 1][j - 1] & B) >> 16);
            }
        }
        /*-----实现均值滤波-----*/
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int a = Math.max(0, i - 1), b = Math.max(0, j - 1);
                int c = Math.min(n - 1, i + 1), d = Math.min(m - 1, j + 1);
                int cnt = (c - a + 1) * (d - b + 1);
                //int srgb = Alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
                int rt = (int) (red[c + 1][d + 1] - red[a][d + 1] - red[c + 1][b] + red[a][b]) / cnt;
                int gt = (int) (green[c + 1][d + 1] - green[a][d + 1] - green[c + 1][b] + green[a][b]) / cnt;
                int bt = (int) (blue[c + 1][d + 1] - blue[a][d + 1] - blue[c + 1][b] + blue[a][b]) / cnt;
                res[i][j] = Alpha << 24 | bt << 16 | gt << 8 | rt;
            }
        }
        return res;
    }


    // 图片数据获取方法，使用二维矩阵表示
    public static int[][] getData(String path) {
        int[][] data = null;
        try {
            BufferedImage bimg = ImageIO.read(new File(path));
            data = new int[bimg.getWidth()][bimg.getHeight()];
            //方式一：通过getRGB()方式获得像素矩阵
            //此方式为沿Height方向扫描
            for (int i = 0; i < bimg.getWidth(); i++) {
                for (int j = 0; j < bimg.getHeight(); j++) {
                    data[i][j] = bimg.getRGB(i, j);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    // 根据对应的十六进制数值返回RGB数值
    public static int[] getRGB(int num) {
        int musk = (1 << 8) - 1;
        int[] res = new int[3];
        for (int i = 0; i < 3; i++) {
            res[i] = num & musk;
            num >>= 8;
        }
        return res;
    }

    // 根据给定的图像数据构建图像
    public static BufferedImage writePIC(int[][] img) {
        int width = img.length, height = img[0].length;
        BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                result.setRGB(i, j, img[i][j]);
            }
        }
        return result;
    }


    public static void main(String[] args) throws IOException {
        Scanner myScanner = new Scanner(System.in);
        System.out.println("输入原图路径");
        String path = myScanner.next();
        int[][] data = MF.getData(path);
        int[][] img = imageSmoother(data);
        BufferedImage res = writePIC(img);
        System.out.println("输入均衡化滤波之后的路径");
        String outputPath = myScanner.next();
        outputPath += "res" + path.split("\\.")[1];
        File outputFile = new File(outputPath);
        ImageIO.write(res, "JPG", outputFile);
    }

}
